#include "../include/netdisk.h"
// 全局变量, 父子线程通信用管道
static int fd[2];
void* threadFunc(void* arg)
{
    train_t* train = (train_t*) arg;
    int ret = 0;
    char ip[128] = {0};
    char port[128] = {0};
    ret = recv(fd[0], ip, sizeof(ip), MSG_WAITALL);      // 接收 ip
    if (ret < 0)
    {
        printf("客户端子线程接收ip失败\n");
        close(fd[0]);
        pthread_exit(NULL);
    }
    ret = recv(fd[0], port, sizeof(port), MSG_WAITALL);  // 接收 port
    if (ret < 0)
    {
        printf("客户端子线程接收port失败\n");
        close(fd[0]);
        pthread_exit(NULL);
    }
    printf("子线程收到: ip=%s, port=%s\n", ip, port);
    if (ret < 0)
    {
        printf("客户端子线程read失败\n");
        close(fd[0]);
        pthread_exit(NULL);
    }
    int sockfd = tcpConnect(ip, port);

    if(sockfd < 0)
    {
        printf("客户端子线程连接服务端失败\n");
        close(fd[0]);
        pthread_exit(NULL);
    }


    printf("train.cmdstat = %d\n", train->cmdstat);
    printf("train.length = %d\n", train->length);
    printf("train.data = %s\n", train->data);
    
    
    // 发送命令
    send(sockfd, train, sizeof(train->cmdstat) + sizeof(train->length) + train->length, MSG_NOSIGNAL);

    train_t trainRecv = {0};
    memset(&trainRecv, 0, sizeof(trainRecv));
    // 先收命令, 确认服务端已经接收到命令
    recv(sockfd, &trainRecv.cmdstat, sizeof(trainRecv.cmdstat), MSG_WAITALL);
    switch (trainRecv.cmdstat)
    {
    case PUTS:
        printf("PUTS命令开始执行......\n");
        transfer_file_by_sendfile(sockfd, train->data);
        printf("PUTS命令执行成功\n");
        break;
    case GETS:
        printf("GETS命令开始执行......\n");
        recv_from_sendfile(sockfd);
        printf("GETS命令执行成功\n");
        break;
    default:
        break;
    }
    close(fd[0]);
    pthread_exit(NULL);
}

int main(int argc, char* argv[])
{   
    // ./client ip port 
    ARGS_CHECK(argc, 3);
    char ip[128] = {0};
    char port[128] = {0};
    memcpy(ip, argv[1], sizeof(ip));
    memcpy(port, argv[2], sizeof(port));
    // 用户登录
    int sockfd = clientLogin(ip, port);
    if(sockfd == -1)
    {
        printf("登录失败, 服务端断开\n");
        return 0;
    }
    else if(sockfd == 1)
    {
        printf("客户断开连接\n");
        return 0;
    }   

    int epfd = epoll_create(1);
    train_t train = {0};
    char buf[4096] = {0};

    epollAdd(epfd, STDIN_FILENO);// 监听键盘输入
    epollAdd(epfd, sockfd);// 监听服务端消息
    struct epoll_event readyset[1024];
// 登录成功之后，可以执行命令和传输文件
    int commandFlag = 0;
    while(1)
    {   if(commandFlag == 0)
        {
            printf("登陆成功!\n");
            commandFlag = 1;
        }
        int readynum = epoll_wait(epfd, readyset, 1024, -1);// -1永久等待
        for (int i = 0; i < readynum; i++)
        {// 遍历就绪集合
            if(readyset[i].data.fd == STDIN_FILENO)
            {
                memset(buf, 0, sizeof(buf));
                memset(&train, 0, sizeof(train));
                int readcount = read(STDIN_FILENO, buf, sizeof(buf));
                if(readcount == 0)
                {
                    printf("客户退出!\n");
                    goto end;
                }
                buf[strlen(buf) - 1] = '\0';
                // printf("test: buf=%s, readcount=%d\n", buf, readcount);               
                /*客户输入命令处理*/
                int ret = commandCheck(buf, &train);
                printf("test: train.cmd = %d| train.length = %d| train.data = %s|\n", train.cmdstat, train.length, train.data);
                if (ret == -1)
                {
                    printf("请重新输入:\n");                   
                    break;
                } 
                // 长短命令分离, puts/gets交给子线程 
                if ( (train.cmdstat == PUTS) || (train.cmdstat == GETS) )
                {
                    socketpair(AF_LOCAL, SOCK_STREAM, 0, fd);  // 全双工通信
                    pthread_t tid;
                    pthread_create(&tid, NULL, threadFunc, &train);
                    send(fd[1], ip, sizeof(ip), MSG_NOSIGNAL);
                    send(fd[1], port, sizeof(port), MSG_NOSIGNAL);
                    close(fd[1]);
                }               
                else
                {// 短命令                    
                    send(sockfd, &train, sizeof(train.cmdstat)+sizeof(train.length)+train.length, MSG_NOSIGNAL);
                    printf("命令发送成功!\n");
                    printf("test: train.cmd = %d| train.length = %d| train.data = %s|\n", train.cmdstat, train.length, train.data);
                    sleep(1);
                }
            }
            else if (readyset[i].data.fd == sockfd)
            {
                // trainRecv 用来接命令执行后的结果                
                train_t trainRecv = {0};
                int ret = 0;
                printf("-----------------\n");                
                switch (train.cmdstat) 
                {
                    case CD:
                        // CD 16
                        printf("CD命令开始执行......\n");                       
                        ret = recv(sockfd, &trainRecv.cmdstat, sizeof(trainRecv.cmdstat), MSG_WAITALL);
                        if (ret <= 0)
                        {
                            printf("服务端断开或发生错误...\n");
                            return 0;
                        }                        
                        // printf("11\n");
                        printf("%d\n", trainRecv.cmdstat);
                        // printf("22\n");
                        if (trainRecv.cmdstat & IS_OK)
                        {// CD命令执行成功
                            recv(sockfd, &trainRecv.length, sizeof(trainRecv.length), MSG_WAITALL);
                            printf("%d\n", trainRecv.length);
                            recv(sockfd, trainRecv.data, trainRecv.length, MSG_WAITALL);
                            printf("%s\n", trainRecv.data);
                            fflush(stdout);
                            printf("CD命令执行完成......\n");
                            break;
                        }
                        else
                        {// CD命令执行失败
                            recv(sockfd, &trainRecv.length, sizeof(trainRecv.length), MSG_WAITALL);
                            printf("%d\n", trainRecv.length);
                            recv(sockfd, trainRecv.data, trainRecv.length, MSG_WAITALL);
                            printf("%s\n", trainRecv.data);
                            fflush(stdout);
                            printf("CD命令执行完成......\n");
                            break;
                        }                       
                        break;
                    case LS:
                        printf("LS命令开始执行......\n");
                        memset(&trainRecv, 0, sizeof(trainRecv));
                        while(1)
                        {
                            memset(&trainRecv, 0, sizeof(trainRecv));
                            ret = recv(sockfd, &trainRecv.cmdstat, sizeof(trainRecv.cmdstat), MSG_WAITALL);
                            if (ret <= 0)
                            {
                                printf("服务端断开或发生错误...\n");
                                continue;
                            }
                            if (trainRecv.cmdstat & OVER)
                            {
                                printf("LS命令执行完成......\n");
                                break;
                            }
                            recv(sockfd, &trainRecv.length, sizeof(trainRecv.length), MSG_WAITALL);
                            recv(sockfd, trainRecv.data, trainRecv.length, MSG_WAITALL); 
                            printf("%s", trainRecv.data);
                            fflush(stdout);
                        }                                          
                        break;
                    case PWD:
                        recv(sockfd, &trainRecv.cmdstat, sizeof(trainRecv.cmdstat), MSG_WAITALL);
                        recv(sockfd, &trainRecv.length, sizeof(trainRecv.length), MSG_WAITALL);
                        recv(sockfd, trainRecv.data, trainRecv.length, MSG_WAITALL);                                           
                        printf("%s", trainRecv.data);
                        fflush(stdout);  
                        break;
                    case MKDIR:

                        break;
                    case RMDIR:

                        break;
                    case REMOVE:

                        break;
                    default:
                        break;      
                }
            
            }
            
        }
    }
        
end:
    close(epfd);
    close(sockfd);
    return 0;
}

